package com.alquimia.truco.dominio.modelo;

import java.util.*;
import java.util.stream.Stream;

/**
 * Created by Ivo on 29/05/2014.
 */
public class Jugador {

    private String nombre;
    private JugadorId jugadorId;
    private List<Carta> cartas;
    private boolean primeroEnJugar;
    private int puntos;

    public Jugador(JugadorId aJugadorId, String aNombre) {
        this();
        setNombre(aNombre);
        setJugadorId(aJugadorId);
    }

    private Jugador() {
        super();
        setPuntos(0);
    }

    protected void sumarPuntos(int aPuntos) {
        setPuntos(puntos() + aPuntos);
    }

    public void nuevasCartas(List<Carta> aCartas) {
        setCartas(aCartas);
    }

    public long puntosEnvido() {

        Palo mPalo = null;
        for (Carta mCarta : cartas()) {
            if (this.cartas().stream().filter(e -> e.palo() == mCarta.palo()).count() > 1) {
                mPalo = mCarta.palo();
                break;
            }
        }

        if (mPalo == null) {
            OptionalInt mCartaMaxima = this.cartas().stream().filter(e -> e.numero() < 10).mapToInt(e -> e.numero()).max();
            return (mCartaMaxima.isPresent()) ? mCartaMaxima.getAsInt() : 0;
        }
        final Palo mPaloRepetido = mPalo;

        Stream<Carta> mCartasStream = this.cartas().stream().filter(e -> e.numero() < 10 && e.palo() == mPaloRepetido);

        IntSummaryStatistics mStreamInfo = mCartasStream.mapToInt(e -> e.numero()).summaryStatistics();

        if (mStreamInfo.getCount() == 3)
            return 20 + this.cartas().stream().filter(e -> e.numero() != mStreamInfo.getMin()).mapToInt(e -> e.numero()).sum();

        if (mStreamInfo.getCount() == 2)
            return 20 + mStreamInfo.getSum();

        return 20 + mStreamInfo.getSum();

    }

    public void realizarJugada(Accion aEstadoAccion){

        Jugada mJugada = new Jugada(this.jugadorId, aEstadoAccion);

    }

    @Override
    public int hashCode() {
        int hashCodeValue = this.jugadorId().hashCode() + this.nombre().hashCode();
        return hashCodeValue;
    }

    @Override
    public boolean equals(Object aObject) {

        boolean equalObjects = false;
        if (aObject != null && aObject.getClass() == this.getClass()) {
            Jugador jugador = (Jugador) aObject;
            equalObjects = jugador.jugadorId().equals(this.jugadorId());
        }

        return equalObjects;
    }

    @Override
    public String toString() {
        return this.getClass().getSimpleName() + "[nombre=" + nombre() + ", jugadorId=" + jugadorId() + "]";
    }

    private void setCartas(List<Carta> aCartas) {
        if (aCartas == null)
            throw new NullPointerException("Las cartas no deben ser nulas.");
        if (aCartas.size() != 3)
            throw new IllegalArgumentException("Deben ser 3 cartas.");

        this.cartas = aCartas;
    }

    public boolean esPrimeroEnJugar() {
        return this.primeroEnJugar;
    }

    public int puntos() {
        return this.puntos;
    }

    public List<Carta> cartas() {
        if (this.cartas == null)
            setCartas(new ArrayList(3));
        else
            return this.cartas;
        return this.cartas;
    }

    public JugadorId jugadorId() {
        return this.jugadorId;
    }

    public String nombre() {
        return this.nombre;
    }

    private void setNombre(String aNombre) {
        if (aNombre.length() < 3 || aNombre.length() > 20)
            throw new IllegalArgumentException("El nombre del jugador debe tener entre 3 y 20 letras.");
        this.nombre = aNombre;
    }

    private void setJugadorId(JugadorId aJugadorId) {

        if(aJugadorId==null)
            throw new NullPointerException("El jugador id no debe ser nulo.");

        this.jugadorId = aJugadorId;
    }

    public void setPrimeroEnJugar(boolean aPrimeroEnJugar) {
        this.primeroEnJugar = aPrimeroEnJugar;
    }

    private void setPuntos(int aPuntos) {
        this.puntos = aPuntos;
    }
}
